#!/bin/bash
# /etc/systemd/system/20-raspibolt-welcome.sh
set -u

# make executable and copy script to /etc/update-motd.d/
# user must be able to execute bitcoin-cli and lncli

# Script configuration
# ------------------------------------------------------------------------------

# set datadir
bitcoin_dir="/data/bitcoin"
lnd_dir="/data/lnd"

# set to mount point of secondary storage. This is used to calculate secondary USB usage %
ext_storage2nd="/mnt/ext"

# set to network device name (usually "eth0" for ethernet, and "wlan0" for wifi)
network_name="wlan0"


# Helper functionality
# ------------------------------------------------------------------------------

# set colors
color_red='\033[0;31m'
color_green='\033[0;32m'
color_yellow='\033[0;33m'
color_grey='\033[0;37m'

# controlled abort on Ctrl-C
trap_ctrlC() {
  echo -e "\r"
  printf "%0.s " {1..80}
  printf "\n"
  exit
}

trap trap_ctrlC SIGINT SIGTERM

# print usage information for script
usage() {
  echo "RaspiBolt Welcome: system status overview
usage: bbb-cmd.sh [--help] [--mock]

This script can be run on startup: make it executable and
copy the script to /etc/update-motd.d/
"
}

# check script arguments
mockmode=0
if [[ ${#} -gt 0 ]]; then
  if [[ "${1}" == "-m" ]] || [[ "${1}" == "--mock" ]]; then
    mockmode=1
  else
    usage
    exit 0
  fi
fi


# Print first welcome message
# ------------------------------------------------------------------------------
printf "
${color_yellow}RaspiBolt %s:${color_grey} Sovereign Bitcoin full node
${color_yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
" "3"

# Gather system data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..40}
echo -ne '\r### Loading System data \r'

# get uptime & load
load=$(w|head -1|sed -E 's/.*load average: (.*)/\1/')
uptime=$(w|head -1|sed -E 's/.*up (.*),.*user.*/\1/'|sed -E 's/([0-9]* days).*/\1/')

# get CPU temp
cpu=$(cat /sys/class/thermal/thermal_zone0/temp)
temp=$((cpu/1000))
if [ ${temp} -gt 60 ]; then
  color_temp="${color_red}\e[7m"
elif [ ${temp} -gt 50 ]; then
  color_temp="${color_yellow}"
else
  color_temp="${color_green}"
fi

# get memory
ram_avail=$(free --mebi | grep Mem | awk '{ print $7 }')

if [ "${ram_avail}" -lt 100 ]; then
  color_ram="${color_red}\e[7m"
else
  color_ram=${color_green}
fi

# get storage
storage_free_ratio=$(printf "%.0f" "$(df | grep "/$" | awk '{ print $4/$2*100 }')") 2>/dev/null
storage=$(printf "%s" "$(df -h|grep '/$'|awk '{print $4}')") 2>/dev/null

if [ "${storage_free_ratio}" -lt 10 ]; then
  color_storage="${color_red}\e[7m"
else
  color_storage=${color_green}
fi

storage2nd_free_ratio=$(printf "%.0f" "$(df  | grep ${ext_storage2nd} | awk '{ print $4/$2*100 }')") 2>/dev/null
storage2nd=$(printf "%s" "$(df -h|grep ${ext_storage2nd}|awk '{print $4}')") 2>/dev/null

if [ -z "${storage2nd}" ]; then
  storage2nd="none"
  color_storage2nd=${color_grey}
else
  storage2nd="${storage2nd} free"
  if [ "${storage2nd_free_ratio}" -lt 10 ]; then
    color_storage2nd="${color_red}\e[7m"
  else
    color_storage2nd=${color_green}
  fi
fi

# get network traffic
network_rx=$(ifconfig ${network_name} | grep 'RX packets' | awk '{ print $6$7 }' | sed 's/[()]//g')
network_tx=$(ifconfig ${network_name} | grep 'TX packets' | awk '{ print $6$7 }' | sed 's/[()]//g')

# Gather application versions
# ------------------------------------------------------------------------------

# GitHub calls for version info, limited to once a day
gitstatusfile="${HOME}/.raspibolt.versions"
gitupdate="0"
if [ ! -f "$gitstatusfile" ]; then
  gitupdate="1"
else
  gitupdate=$(find "${gitstatusfile}" -mtime +1 | wc -l)
fi
if [ "${gitupdate}" -eq "1" ]; then
  # Calls to github
  btcgit=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')
  lndgit=$(curl -s https://api.github.com/repos/lightningnetwork/lnd/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')
  # Electrs, RPC Explorer and RTL dont have a latest release, just tags
  electrsgit=$(curl -s https://api.github.com/repos/romanz/electrs/tags | jq -r '.[0].name')
  btcrpcexplorergit=$(curl -s https://api.github.com/repos/janoside/btc-rpc-explorer/tags | jq -r '.[0].name')
  rtlgit=$(curl -s https://api.github.com/repos/Ride-The-Lightning/RTL/tags | jq -r '.[] | select(.name | test("rc") | not) | .name' | head -n 1)
  # write to file TODO: convert to JSON for sanity
  printf "%s\n%s\n%s\n%s\n%s\n" "${btcgit}" "${lndgit}" "${electrsgit}" "${btcrpcexplorergit}" "${rtlgit}" > "${gitstatusfile}"
else
  # read from file
  btcgit=$(sed -n '1p' < "${gitstatusfile}")
  lndgit=$(sed -n '2p' < "${gitstatusfile}")
  electrsgit=$(sed -n '3p' < "${gitstatusfile}")
  btcrpcexplorergit=$(sed -n '4p' < "${gitstatusfile}")
  rtlgit=$(sed -n '5p' < "${gitstatusfile}")

  # fill if not yet set
  if [ -z "$btcgit" ]; then
    btcgit=$(curl -s https://api.github.com/repos/bitcoin/bitcoin/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')
  fi
  if [ -z "$lndgit" ]; then
    lndgit=$(curl -s https://api.github.com/repos/lightningnetwork/lnd/releases/latest | grep -oP '"tag_name": "\K(.*)(?=")')
  fi
  if [ -z "$electrsgit" ]; then
    electrsgit=$(curl -s https://api.github.com/repos/romanz/electrs/tags | jq -r '.[0].name')
  fi
  if [ -z "$btcrpcexplorergit" ]; then
    btcrpcexplorergit=$(curl -s https://api.github.com/repos/janoside/btc-rpc-explorer/tags | jq -r '.[0].name')
  fi
  if [ -z "$rtlgit" ]; then
    rtlgit=$(curl -s https://api.github.com/repos/Ride-The-Lightning/RTL/tags | jq -r '.[] | select(.name | test("rc") | not) | .name' | head -n 1)
  fi
  printf "%s\n%s\n%s\n%s\n%s\n" "${btcgit}" "${lndgit}" "${electrsgit}" "${btcrpcexplorergit}" "${rtlgit}" > "${gitstatusfile}"
fi

# create variable btcversion
btcpi=$(bitcoin-cli -version |sed -n 's/^.*version //p')
case "${btcpi}" in
  *"${btcgit}"*)
    btcversion="$btcpi"
    btcversion_color="${color_green}"
    ;;
  *)
    btcversion="$btcpi"" Update!"
    btcversion_color="${color_red}"
    ;;
esac


# Gather Bitcoin Core data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..50}
echo -ne '\r### Loading Bitcoin Core data \r'

bitcoind_running=$(systemctl is-active bitcoind)
bitcoind_color="${color_green}"
if [ -z "${bitcoind_running##*inactive*}" ]; then
  bitcoind_running="down"
  bitcoind_color="${color_red}\e[7m"
else
  bitcoind_running="up"
fi
btc_path=$(command -v bitcoin-cli)
if [ -n "${btc_path}" ]; then
  btc_title="฿itcoin"
  chain="$(bitcoin-cli -datadir=${bitcoin_dir} getblockchaininfo | jq -r '.chain')"

  btc_title="${btc_title} (${chain}net)"

  # get sync status
  block_chain="$(bitcoin-cli -datadir=${bitcoin_dir} getblockchaininfo | jq -r '.headers')"
  block_verified="$(bitcoin-cli -datadir=${bitcoin_dir} getblockchaininfo | jq -r '.blocks')"
  block_diff=$(("${block_chain}" - "${block_verified}"))

  progress="$(bitcoin-cli -datadir=${bitcoin_dir} getblockchaininfo | jq -r '.verificationprogress')"
  sync_percentage=$(printf "%.2f%%" "$(echo "${progress}" | awk '{print 100 * $1}')")

  if [ "${block_diff}" -eq 0 ]; then      # fully synced
    sync="OK"
    sync_color="${color_green}"
    sync_behind="[#${block_chain}]"
  elif [ "${block_diff}" -eq 1 ]; then    # fully synced
    sync="OK"
    sync_color="${color_green}"
    sync_behind="-1 block"
  elif [ "${block_diff}" -le 10 ]; then   # <= 10 blocks behind
    sync="Behind"
    sync_color="${color_red}"
    sync_behind="-${block_diff} blocks"
  else
    sync="In progress"
    sync_color="${color_red}"
    sync_behind="${sync_percentage}"
  fi

  # get mem pool transactions
  mempool="$(bitcoin-cli -datadir=${bitcoin_dir} getmempoolinfo | jq -r '.size')"

  # get connection info
  connections="$(bitcoin-cli -datadir=${bitcoin_dir} getnetworkinfo | jq .connections)"
  inbound="$(bitcoin-cli -datadir=${bitcoin_dir} getpeerinfo | jq '.[] | select(.inbound == true)' | jq -s 'length')"
  outbound="$(bitcoin-cli -datadir=${bitcoin_dir} getpeerinfo | jq '.[] | select(.inbound == false)' | jq -s 'length')"
fi

# create variable btcversion
btcpi=$(bitcoin-cli -version |sed -n 's/^.*version //p')
case "${btcpi}" in
  *"${btcgit}"*)
    btcversion="$btcpi"
    btcversion_color="${color_green}"
    ;;
  *)
    btcversion="$btcpi"" Update!"
    btcversion_color="${color_red}"
    ;;
esac


# Gather LND data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..60}
echo -ne '\r### Loading LND data \r'

if [ "${chain}" = "test" ]; then
  macaroon_path="${lnd_dir}/data/chain/bitcoin/testnet/readonly.macaroon"
else
  macaroon_path="${lnd_dir}/data/chain/bitcoin/mainnet/readonly.macaroon"
fi
lnd_running=$(systemctl is-active lnd)
lnd_color="${color_green}"
if [ -z "${lnd_running##*inactive*}" ]; then
  lnd_running="down"
  lnd_color="${color_red}\e[7m"
else
  if [ -z "${lnd_running##*failed*}" ]; then
    lnd_running="down"
    lnd_color="${color_red}\e[7m"
  else
    lnd_running="up"
  fi
fi
if [ -z "${lnd_running##*up*}" ] ; then
  lncli="/usr/local/bin/lncli --macaroonpath=${macaroon_path} --tlscertpath=${lnd_dir}/tls.cert"
  $lncli getinfo 2>&1 | grep "Please unlock" >/dev/null
  wallet_unlocked=$?
else
  wallet_unlocked=0
fi
printf "%0.s#" {1..63}
echo -ne '\r### Loading LND data \r'

if [ "$wallet_unlocked" -eq "0" ] ; then
  alias_color="${color_red}"
  ln_alias="Wallet Locked"
  ln_walletbalance="?"
  ln_channelbalance="?"
  ln_channels_online="?"
  ln_channels_total="?"
  ln_connect_addr=""
  ln_external=""
  ln_pendingopen="?"
  ln_pendingforce="?"
  ln_waitingclose="?"
  ln_pendinglocal="?"
  sum_balance="?"
  if [ $lnd_running = "up" ]; then
    ln_connect_guidance="You must first unlock your wallet:   lncli unlock"
  else
    ln_connect_guidance="The LND service is down. Start the service:   sudo systemctl start lnd"
  fi
else
  alias_color="${color_grey}"
  ln_alias="$(${lncli} getinfo | jq -r '.alias')" 2>/dev/null
  ln_walletbalance="$(${lncli} walletbalance | jq -r '.confirmed_balance')" 2>/dev/null
  ln_channelbalance="$(${lncli} channelbalance | jq -r '.balance')" 2>/dev/null

  printf "%0.s#" {1..66}

  echo -ne '\r### Loading LND data \r'

  ln_channels_online="$(${lncli} getinfo | jq -r '.num_active_channels')" 2>/dev/null
  ln_channels_total="$(${lncli} listchannels | jq '.[] | length')" 2>/dev/null
  ln_connect_addr="$(${lncli} getinfo | jq -r '.uris[0]')" 2>/dev/null
  ln_connect_guidance="lncli connect ${ln_connect_addr}"
  ln_external="$(echo "${ln_connect_addr}" | tr "@" " " |  awk '{ print $2 }')" 2>/dev/null
  if [ -z "${ln_external##*onion*}" ]; then
    ln_external="Using TOR Address"
  fi

  printf "%0.s#" {1..70}
  echo -ne '\r### Loading LND data \r'

  ln_pendingopen=$($lncli pendingchannels  | jq '.pending_open_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}')
  if [ -z "${ln_pendingopen}" ]; then
    ln_pendingopen=0
  fi

  ln_pendingforce=$($lncli pendingchannels  | jq '.pending_force_closing_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}')
  if [ -z "${ln_pendingforce}" ]; then
    ln_pendingforce=0
  fi

  ln_waitingclose=$($lncli pendingchannels  | jq '.waiting_close_channels[].channel.local_balance|tonumber ' | awk '{sum+=$0} END{print sum}')
  if [ -z "${ln_waitingclose}" ]; then
    ln_waitingclose=0
  fi

  echo -ne '\r### Loading LND data \r'

  ln_pendinglocal=$((ln_pendingopen + ln_pendingforce + ln_waitingclose))

  sum_balance=0
  if [ -n "${ln_channelbalance}" ]; then
    sum_balance=$((ln_channelbalance + sum_balance ))
  fi
  if [ -n "${ln_walletbalance}" ]; then
    sum_balance=$((ln_walletbalance + sum_balance ))
  fi
  if [ -n "$ln_pendinglocal" ]; then
    sum_balance=$((sum_balance + ln_pendinglocal ))
  fi
fi

#create variable lndversion
lndpi=$(lncli getinfo | sed -n 's/^\(.*\)=\(.\+\?\)"\(.*\)/\2/p')
if [ "${lndpi}" = "${lndgit}" ]; then
  lndversion="${lndpi}"
  lndversion_color="${color_green}"
else
  lndversion="${lndpi}"" Update!"
  lndversion_color="${color_red}"
fi

#get channel.db size
channel_db_size=$(du -h ${lnd_dir}/data/graph/mainnet/channel.db | awk '{print $1}')


# Gather Electrs data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..74}
echo -ne '\r### Loading Electrum data \r'

electrs_running=$(systemctl is-active electrs)
electrs_color="${color_green}"
if [ -z "${electrs_running##*inactive*}" ]; then
  electrs_running="down"
  electrs_color="${color_red}\e[7m"
  electrsversion=""
  electrsversion_color="${color_red}"
else
  electrs_running="up"
  electrspi=$(echo '{"jsonrpc": "2.0", "method": "server.version", "params": [ "raspibolt", "1.4" ], "id": 0}' | netcat 127.0.0.1 50001 -q 1 | jq -r '.result[0]' | awk '{print "v"substr($1,9)}')
  if [ "$electrspi" = "$electrsgit" ]; then
    electrsversion="$electrspi"
    electrsversion_color="${color_green}"
  else
    electrsversion="$electrspi"" Update!"
    electrsversion_color="${color_red}"
  fi
fi


# Gather Bitcoin Explorer data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..76}
echo -ne '\r### Loading Block Explorer data \r'

#btcrpcexplorer
btcrpcexplorer_running=$(systemctl is-active btcrpcexplorer)
btcrpcexplorer_color="${color_green}"
if [ -z "${btcrpcexplorer_running##*inactive*}" ]; then
  btcrpcexplorer_running="down"
  btcrpcexplorer_color="${color_red}\e[7m"
  btcrpcexplorerversion=""
  btcrpcexplorerversion_color="${color_red}"
else
  btcrpcexplorer_running="up"
  btcrpcexplorerpi=v$(cd /home/btcrpcexplorer/btc-rpc-explorer; npm version | grep -oP "'btc-rpc-explorer': '\K(.*)(?=')")
  if [ "$btcrpcexplorerpi" = "$btcrpcexplorergit" ]; then
    btcrpcexplorerversion="$btcrpcexplorerpi"
    btcrpcexplorerversion_color="${color_green}"
  else
    btcrpcexplorerversion="$btcrpcexplorerpi"" Update!"
    btcrpcexplorerversion_color="${color_red}"
  fi
fi

# Gather RTL data
# ------------------------------------------------------------------------------
printf "%0.s#" {1..78}
echo -ne '\r### Loading RTL data \r'

#rtl
rtl_running=$(systemctl is-active rtl)
rtl_color="${color_green}"
if [ -z "${rtl_running##*inactive*}" ]; then
  rtl_running="down"
  rtl_color="${color_red}\e[7m"
  rtlversion=""
  rtlversion_color="${color_red}"
else
  rtl_running="up"
  rtlpi=v$(cd /home/rtl/RTL; npm version | grep -oP "rtl: '\K(.*)(?=-beta')")
  if [ "$rtlpi" = "$rtlgit" ]; then
    rtlversion="$rtlpi"
    rtlversion_color="${color_green}"
  else
    rtlversion="$rtlpi"" Update!"
    rtlversion_color="${color_red}"
  fi
fi

# Mockmode overrides data for documentation images
# ------------------------------------------------------------------------------

if [ "${mockmode}" -eq 1 ]; then
  ln_alias="MyRaspiBolt-version3"
  ln_walletbalance="100000"
  ln_channelbalance="200000"
  ln_pendinglocal="50000"
  sum_balance="350000"
  ln_channels_online="34"
  ln_channels_total="36"
  ln_connect_guidance="lncli connect c55c05e9148e4e0f120835a6384348dd4d91f77bb1adf256694391bf81a07f03ef@klra7gtbc1j322399pq87bk47ny38brjomvfdg3vb6k3ggahan2dzlyd.onion:9735"
fi

# Render output
# ------------------------------------------------------------------------------

echo -ne "\033[2K"
printf "${color_grey}cpu temp: ${color_temp}%-2s°C${color_grey}  tx: %-10s storage:   ${color_storage}%-11s ${color_grey}  load: %s
${color_grey}up: %-10s  rx: %-10s 2nd drive: ${color_storage2nd}%-11s${color_grey}   available mem: ${color_ram}%sM
${color_yellow}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
${color_green}     .~~.   .~~.      ${color_yellow}%-22s${bitcoind_color}%-4s${color_grey}   ${color_yellow}%-20s${lnd_color}%-4s
${color_green}    '. \ ' ' / .'     ${btcversion_color}%-26s ${lndversion_color}%-24s
${color_red}     .~ .~~~${color_yellow}.${color_red}.~.      ${color_grey}Sync    ${sync_color}%-18s ${alias_color}%-24s
${color_red}    : .~.'${color_yellow}／/${color_red}~. :     ${color_grey}Mempool %-18s ${color_grey}฿%17s sat
${color_red}   ~ (  ${color_yellow}／ /_____${color_red}~    ${color_grey}Peers   %-22s ${color_grey}⚡%16s sat
${color_red}  ( : ${color_yellow}／____   ／${color_red} )                              ${color_grey}⏳%16s sat
${color_red}   ~ .~ (  ${color_yellow}/ ／${color_red}. ~    ${color_yellow}%-20s${electrs_color}%-4s   ${color_grey}∑%17s sat
${color_red}    (  : '${color_yellow}/／${color_red}:  )     ${electrsversion_color}%-26s ${color_grey}%s/%s channels
${color_red}     '~ .~${color_yellow}°${color_red}~. ~'                                 ${color_grey}Channel.db size: ${color_green}%s
${color_red}         '~'          ${color_yellow}%-20s${color_grey}${btcrpcexplorer_color}%-4s
${color_red}                      ${btcrpcexplorerversion_color}%-24s   ${color_yellow}%-20s${rtl_color}%-4s
${color_red}                                                 ${rtlversion_color}%-24s

${color_grey}For others to connect to this lightning node
${color_grey}%s

" \
"${temp}" "${network_tx}" "${storage} free" "${load}" \
"${uptime}" "${network_rx}" "${storage2nd}" "${ram_avail}" \
"${btc_title}" "${bitcoind_running}" "Lightning (LND)" "${lnd_running}" \
"${btcversion}" "${lndversion}" \
"${sync} ${sync_behind}" "${ln_alias}" \
"${mempool} tx" "${ln_walletbalance}" \
"${connections} (📥${inbound} /📤${outbound})" "${ln_channelbalance}" \
"${ln_pendinglocal}" \
"Electrum" "${electrs_running}" "${sum_balance}" \
"${electrsversion}" "${ln_channels_online}" "${ln_channels_total}" \
"${channel_db_size}" \
"Block Explorer" "${btcrpcexplorer_running}" \
"${btcrpcexplorerversion}" "RTL" "${rtl_running}" \
"${rtlversion}" \
"${ln_connect_guidance}"
